package com.gitee.melin.bee.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gitee.melin.bee.core.support.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * huaixin 2021/12/6 5:49 PM
 */
public class MapperUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(MapperUtils.class);

    private final static ObjectMapper objectMapper = new ObjectMapper();

    public static ObjectMapper getInstance() {
        return objectMapper;
    }

    static {
        try {
            Class<?> clazz = Class.forName("com.fasterxml.jackson.datatype.jdk8.Jdk8Module");
            objectMapper.registerModule((Module) clazz.newInstance());
        } catch (Throwable e) {
            LOGGER.warn("jackson-datatype-jdk8 not exist");
        }
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    }

    /**
     * 转换为 JSON 字符串
     *
     * @param obj
     */
    public static String toJSONString(Object obj) {
        return toJSONString(obj, false);
    }

    /**
     * 转换为 JSON 字符串
     *
     * @param obj
     */
    public static String toJSONString(Object obj, boolean pretty) {
        try {
            if (pretty) {
                return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
            } else {
                return objectMapper.writeValueAsString(obj);
            }
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * 转换为 JavaBean
     *
     * @param jsonString
     */
    public static <T> Result<T> toJavaResult(String jsonString, TypeReference<Result<T>> ref) {
        try {
            objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
            return objectMapper.readValue(jsonString, ref);
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * 转换为 JavaBean
     *
     * @param jsonString
     */
    public static <T> T toJavaObject(String jsonString, Class<T> clazz) {
        try {
            objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
            return objectMapper.readValue(jsonString, clazz);
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * 转换为 JavaBean
     *
     * @param jsonString
     * @param ref
     * @throws IOException
     */
    public static <T> T toJavaObject(String jsonString, TypeReference<T> ref) {
        try {
            objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
            return objectMapper.readValue(jsonString, ref);
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * 字符串转换为 Map<String, Object>
     *
     * @param jsonInput
     * @throws IOException
     */
    public static <T> Map<String, T> toJavaMap(String jsonInput) {
        try {
            TypeReference<HashMap<String, T>> typeRef = new TypeReference<HashMap<String, T>>() {};
            return objectMapper.readValue(jsonInput, typeRef);
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * 将 Map 转换为 Result
     *
     * @param jsonInput
     */
    public static <R> Result<R> jsonToResult(String jsonInput) {
        try {
            Map<String, Object> map = objectMapper.readValue(jsonInput,
                    new TypeReference<Map<String, Object>>() {});

            TypeReference<Result<R>> typeRef = new TypeReference<Result<R>>() { };
            return objectMapper.convertValue(map, typeRef);
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }
}
